// X-Chat TIGCC, Ti-Gen, Fedora and Hypersonicsoft News Fetcher by Kevin Kofler
// Portions lifted from the X-Chat plugin examples by Peter Zelezný (GPLed) and
// from testfetch.c by Lyle Hanson (Public Domain).

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <locale.h>
#include <iconv.h>
#include "xchat-plugin.h"
#include "http_fetcher.h"

#define MAXNEWS 5

int verbose_debug = 0;	// avoid linkage error

static xchat_plugin *ph;   /* plugin handle */
static iconv_t conv;

static int timeout_cb(void *userdata)
{
  int ret, fileLen;
  const char *url=NULL;     /* Pointer to the url you want */
  const char *msg=NULL;
  char *fileBuf;                          /* Pointer to downloaded data */
  int newssite = *(int*)(userdata+sizeof(xchat_context*));
  const char *nick = userdata+sizeof(xchat_context*)+sizeof(int);
  xchat_set_context(ph, *(xchat_context**)userdata);

  switch (newssite) {
    case 0:
      url = "tigcc.ticalc.org/newsheadlines.txt";
      msg = "news from http://tigcc.ticalc.org/";
      break;
    case 1:
      url = "tigcc.ticalc.org/linux/newsheadlines.txt";
      msg = "news from http://tigcc.ticalc.org/linux/";
      break;
    case 2:
      url = "www.hypersonicsoft.org/news_tigcc.txt";
      msg = "news from http://www.hypersonicsoft.org/";
      break;
    case 3:
      url = "www.tigen.org/feed/atom.php?id=1";
      msg = "news from http://www.tigen.org/";
      break;
    case 4:
      url = "www.tigen.org/feed/atom.php?id=21";
      msg = "unofficial news from http://www.tigen.org/";
      break;
    case 5:
      url = "http://fedoranews.org/cms/node/feed";
      msg = "news from http://www.fedoranews.org/";
      break;
  }
  xchat_commandf(ph, "notice %s Fetching %s", nick, msg);
  ret = hfetcher_fetch(url, &fileBuf, &fileLen);  /* Downloads page */
  if(ret == -1)                       /* All HTTP Fetcher functions return */
    {                               /*  -1 on error. */
      const char *err=hfetcher_strerror();
      xchat_commandf(ph, "notice %s E %s", nick, err);
    }
  else if(ret < 200 || ret > 299)     /* 2xx is HTTP success code */
      xchat_commandf(ph, "notice %s E HTTP %d", nick, ret);
  else
    {
      char filebuffer[3*fileLen+1], datebuffer[100], *p;
      int c = 0, nc = 0, y, m, d, hr, mn, sc;
      char title[256], author[256];
      struct tm tm={};
#ifdef __WIN32__
      const
#endif
      char *inbuf = fileBuf; char *outbuf = filebuffer;
      size_t inleft = fileLen, outleft = 3*fileLen;
      memset(filebuffer, 0, 3*fileLen+1);
      if (newssite==1 || newssite==2 || newssite==5)
        memcpy(filebuffer, fileBuf, fileLen);
      else
        iconv(conv, &inbuf, &inleft, &outbuf, &outleft);
      p=strtok(filebuffer,"\n");
      while (p && nc < MAXNEWS) {
        if (*p && *p!='\r') {
          if (p[strlen(p)-1]=='\r') p[strlen(p)-1]=0;
          if (newssite==5) {
            switch (c++) {
              case 12:
                if (!strcmp(p,"</channel>"))
                  c = 2000;
                else if (sscanf(p,"<item>")<0)
                  goto parse_error;
                break;
              case 13:
                if (sscanf(p," <title>%255[^<]</title>",title)<1)
                  goto parse_error;
                while (strstr(title,"&#039;")) {
                  char *q=strstr(title,"&#039;");
                  *(q++)='\'';
                  memmove(q,q+5,strlen(q+4));
                }
                break;
              case 14 ... 999:
                if (!strcmp(p,"</description>"))
                  c = 1000;
                break;
              case 1000:
                if (strncmp(p," <pubDate>",10)) {
                  if (sscanf(p," <category domain=\"%*[^\"]\">%255[^<]</category>",author)<1)
                    goto parse_error;
                  break;
                } else *author=0;
              case 1001:
                if (!strncmp(p," <category ",11)) {
                  c = 1001;
                  break;
                }
                if (sscanf(p," <pubDate>%*3c, %d %3c %d %2d:%2d:%2d %*5c</pubDate>",&d,datebuffer,&y,&hr,&mn,&sc)<6)
                  goto parse_error;
                const char *oldlocale;
                if (!strncmp(datebuffer,"Jan",3)) m=1;
                else if (!strncmp(datebuffer,"Feb",3)) m=2;
                else if (!strncmp(datebuffer,"Mar",3)) m=3;
                else if (!strncmp(datebuffer,"Apr",3)) m=4;
                else if (!strncmp(datebuffer,"May",3)) m=5;
                else if (!strncmp(datebuffer,"Jun",3)) m=6;
                else if (!strncmp(datebuffer,"Jul",3)) m=7;
                else if (!strncmp(datebuffer,"Aug",3)) m=8;
                else if (!strncmp(datebuffer,"Sep",3)) m=9;
                else if (!strncmp(datebuffer,"Oct",3)) m=10;
                else if (!strncmp(datebuffer,"Nov",3)) m=11;
                else if (!strncmp(datebuffer,"Dec",3)) m=12;
                else goto parse_error;
                tm.tm_year = y-1900; tm.tm_mon = m-1; tm.tm_mday = d;
                tm.tm_hour = hr; tm.tm_min = mn; tm.tm_sec = sc;
                oldlocale = setlocale(LC_TIME,NULL);
                setlocale(LC_TIME,"C");
                strftime(datebuffer, 99, "%B %d, %Y %H:%M:%S", &tm);
                setlocale(LC_TIME,oldlocale);
                xchat_commandf(ph, "notice %s %s  %s", nick, datebuffer, author);
                xchat_commandf(ph, "notice %s %s", nick, title);
                c=1002;
                nc++;
                break;
              case 1002:
                if (sscanf(p,"</item>")<0)
                  goto parse_error;
                c = 12;
                break;
              default:
                break;
            }
          } else if (newssite>2) {
            switch (c++) {
              case 5:
                if (sscanf(p," <title>%255[^<]</title>",title)<1)
                  goto parse_error;
                break;
              case 7:
                if (strcmp(p,"\t\t<author>")) {
                  *author = 0;
                  goto case_10;
                }
                break;
              case 8:
                if (sscanf(p," <name>%255[^<]</name>",author)<1)
                  goto parse_error;
                break;
              case 9:
                if (sscanf(p," </author>")<0)
                  goto parse_error;
                break;
              case 10:
              case_10:
                if (sscanf(p," <issued>%4d-%2d-%2dT%2d:%2d:%2dZ</issued>",
                           &y,&m,&d,&hr,&mn,&sc)<6)
                  goto parse_error;
                const char *oldlocale;
                tm.tm_year = y-1900; tm.tm_mon = m-1; tm.tm_mday = d;
                tm.tm_hour = hr; tm.tm_min = mn; tm.tm_sec = sc;
                oldlocale = setlocale(LC_TIME,NULL);
                setlocale(LC_TIME,"C");
                strftime(datebuffer, 99, "%B %d, %Y %H:%M:%S", &tm);
                setlocale(LC_TIME,oldlocale);
                xchat_commandf(ph, "notice %s %s  %s", nick, datebuffer, author);
                xchat_commandf(ph, "notice %s %s", nick, title);
                c = 11;
                nc++;
                break;
              case 11:
                if (sscanf(p," <modified>%4d-%2d-%2dT%2d:%2d:%2dZ</modified>",
                           &y,&m,&d,&hr,&mn,&sc)<6)
                  c = 4;
                else
                  c = 3;
                break;
              default:
                break;
            }
          } else {
            if (strcmp(p,"TIGCC News Format")) {
              if (!((c++)&1)) {
                const char *oldlocale;
                if (sscanf(p,"%4d%2d%2d",&y,&m,&d)<3) goto parse_error;
                tm.tm_year = y-1900; tm.tm_mon = m-1; tm.tm_mday = d;
                oldlocale = setlocale(LC_TIME,NULL);
                setlocale(LC_TIME,"C");
                strftime(datebuffer, 99, "%B %d, %Y", &tm);
                setlocale(LC_TIME,oldlocale);
                xchat_commandf(ph, "notice %s %s", nick, datebuffer);
              } else {
                xchat_commandf(ph, "notice %s %s", nick, p);
                nc++;
              }
            }
          }
        }
        p=strtok(NULL,"\n");
      }
    }
  if (0) {
parse_error:
    xchat_commandf(ph, "notice %s E News feed parse error", nick);
  }
  free(fileBuf);
  free(userdata);
  return 0;
}

static int chanmsg_cb(char *word[], void *userdata)
{
  int newssite;
  if (!strcmp(word[2],"!tigccnews"))
    newssite = 0;
  else if (!strcmp(word[2],"!tigcclinuxnews"))
    newssite = 1;
  else if (!strcmp(word[2],"!hsnews"))
    newssite = 2;
  else if (!strcmp(word[2],"!tigennews"))
    newssite = 3;
  else if (!strcmp(word[2],"!tigenunews"))
    newssite = 4;
  else if (!strcmp(word[2],"!fedoranews"))
    newssite = 5;
  else
    return XCHAT_EAT_NONE;
  char *buffer=malloc(sizeof(xchat_context*)+sizeof(int)+strlen(word[1])+1);
  *(xchat_context**)buffer=xchat_get_context(ph);
  *(int*)(buffer+sizeof(xchat_context*))=newssite;
  strcpy(buffer+sizeof(xchat_context*)+sizeof(int),word[1]);
  xchat_hook_timer(ph, 1, timeout_cb, buffer);
  return XCHAT_EAT_NONE;
}

__declspec(dllexport)
int xchat_plugin_init(xchat_plugin *plugin_handle,
                      char **plugin_name,
                      char **plugin_desc,
                      char **plugin_version,
                      char *arg)
{
   /* we need to save this for use with any xchat_* functions */
   ph = plugin_handle;

   *plugin_name = "X-Chat TIGCC/Ti-Gen/Fedora/Hypersonicsoft News";
   *plugin_desc = "Shows TIGCC news on !tigccnews, Ti-Gen news on !tigennews, "
                  "Ti-Gen unofficial news on !tigenunews, Fedora news on "
                  "!fedoranews and Hypersonicsoft news on !hsnews";
   *plugin_version = "0.50";

   conv = iconv_open("UTF-8", "CP1252");

   xchat_hook_print(ph, "Channel Message", XCHAT_PRI_NORM, chanmsg_cb, NULL);
   xchat_hook_print(ph, "Your Message", XCHAT_PRI_NORM, chanmsg_cb, NULL);
   xchat_hook_print(ph, "Private Message", XCHAT_PRI_NORM, chanmsg_cb, NULL);
   xchat_hook_print(ph, "Private Message to Dialog", XCHAT_PRI_NORM, chanmsg_cb, NULL);

   xchat_print(ph, "TIGCC/Ti-Gen/Fedora/Hypersonicsoft News plugin loaded successfully!\n");

   return 1;       /* return 1 for success */
}

__declspec(dllexport)
int xchat_plugin_deinit(void)
{
   iconv_close(conv);

   xchat_print(ph, "TIGCC/Ti-Gen/Fedora/Hypersonicsoft News plugin unloaded successfully!\n");

   return 1;       /* return 1 for success */
}
